#!/usr/bin/env python
#!/usr/bin/env python
"""
Acorn-SDR (A Collaboration of Radio Nodes)
(c) Bob Cowdery (G3UKB) 2009

File: gtk_dashboard_gui.py
Date: July 2009

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

The author can be reached by email at

bob@g3ukb.co.uk

========================================================================
Module Description:

A dashboard GUI using GTK+.

"""

#-----------------------------------------------------------------------
# System imports
import sys
import os
from time import sleep
import subprocess

# Import GTK libraries
try:
  import pygtk
  #tell pyGTK, if possible, that we want GTKv2
  pygtk.require("2.0")
except:
  #Some distributions come with GTK2, but not pyGTK
  pass
try:
  import gtk
  import gtk.glade
  import gobject
except:
  print "You need to install pyGTK or GTKv2 ",
  print "or set your PYTHONPATH correctly."
  print "try: export PYTHONPATH=",
  print "/usr/local/lib/python2.2/site-packages/"
  sys.exit(1)

# Application imports
import utils

#======================================================================
# The GUI class.
class DashboardGui:
  
    #---------------------------------------------------------------------
    def __init__(self, glade_path, persist_service, lc_pub, start_callback, stop_callback, quit_callback):
    
        self.persist = persist_service
        self.start_callback = start_callback
        self.stop_callback = stop_callback
        self.quit_callback = quit_callback
        self.lc_pub = lc_pub
        # Allow threads, without this the gui will hang all python threads
        # We don't actually use any Python threads right now but its very
        # disconcerting if you do and find they block, so leave this in
        gtk.gdk.threads_init()
        # Initialise the glade built ui
        # Load the main window
        windowname = "Dashboard"
        # This loads a widget tree from the XML definition in the glade file
        self.main_tree=gtk.glade.XML (glade_path, windowname)
        # Get and show the main window
        w=self.main_tree.get_widget(windowname)
        w.show_all()
    
        # Wire up the top level window events
        # All events are set up in Glade, just match the event names here
        dic = {
            "on_trv_profile_cursor_changed" : self.profile_changed,
            
            "on_b_ozy_load_clicked" : self.bozy_load,
            
            "on_b_execute_clicked" : self.bexecute,
            "on_b_close_clicked" : self.bclose,
            "on_b_refresh_clicked" : self.brefresh,
            "on_b_quit_clicked" : self.bquit,
            
            "on_b_new_sub_clicked" : self.bnew_sub,
            "on_b_new_rx_disp_clicked" : self.bnew_rx_disp,
            "on_b_new_tx_clicked" : self.bnew_tx,
            "on_b_new_tx_disp_clicked" : self.bnew_tx_disp,
            
            
        }
    
        # This will connect up all the events in one hit
        self.main_tree.signal_autoconnect (dic)
    
        # Now we need a reference to all the controls
        # A bit long winded but easy to follow
        # All controls in the tree must have a unique name
        self.profiles = self.main_tree.get_widget('trv_profile')
        self.description = self.main_tree.get_widget('txv_description')
        
        self.ozy_load = self.main_tree.get_widget('b_ozy_load')
        
        self.execute = self.main_tree.get_widget('b_execute')
        self.close = self.main_tree.get_widget('b_close')
        self.refresh = self.main_tree.get_widget('b_refresh')
        self.exit = self.main_tree.get_widget('b_exit')
        
        self.new_sub = self.main_tree.get_widget('b_new_sub')
        self.new_rx_disp = self.main_tree.get_widget('b_new_rx_disp')
        self.new_tx = self.main_tree.get_widget('b_new_tx')
        self.new_tx_disp = self.main_tree.get_widget('b_new_tx_disp')
        
        self.execute.set_sensitive(False)
        self.close.set_sensitive(False)
        self.refresh.set_sensitive(False)
        self.new_sub.set_sensitive(False)
        self.new_rx_disp.set_sensitive(False)
        self.new_tx.set_sensitive(False)
        self.new_tx_disp.set_sensitive(False)
    
        # Populate the treeview
        treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.profiles.set_model(treestore)
        cell_renderer = gtk.CellRendererText()
        col = gtk.TreeViewColumn('Type', cell_renderer, text=0)
        col.set_resizable(True)
        self.profiles.append_column(col)
        col = gtk.TreeViewColumn('Profile', cell_renderer, text=1)
        col.set_resizable(True)
        self.profiles.append_column(col)
        profiles = self.persist.getProfiles()
        profile_list = profiles.rsplit(',')
        profile_dict = {}
        # Stash our profiles in a dictionary
        for profile in profile_list:
          items = profile.rsplit(':')
          if items[0] <> 'dashboard':
            if items[0] in profile_dict:
              profile_dict[items[0]][1].append(items[1])
            else:
              profile_dict[items[0]] = [None,[items[1]]]
        # Add the root items to the tree
        for key in profile_dict.keys():
            iter = self.insert_row(treestore, None, key, '')
            profile_dict[key][0] = iter
        # Add the rows to the roots
        for value in profile_dict.values():
          for profile_item in value[1]:
            self.insert_row(treestore, value[0], '', profile_item)
        
        # Create a text buffer for the text view
        self.textbuffer = gtk.TextBuffer(table=None)
        self.description.set_buffer(self.textbuffer)

        self.current_profile = None
        
        # Get the launch paths
        HOME = os.environ['ACORN_HOME']
        self.ice_config = utils.persist_get(self.persist, 'Profile', 'path.iceconfig')
        self.ozy_fw_path = utils.persist_get(self.persist, 'Profile', 'path.ozyfw')
        self.console_path = HOME + utils.persist_get(self.persist, 'Profile', 'path.DEFAULT_GUI')
        self.display_path = HOME + utils.persist_get(self.persist, 'Profile', 'path.DEFAULT_DISPLAY')
        self.tx_console_path = HOME + utils.persist_get(self.persist, 'Profile', 'path.DEFAULT_TX_GUI')
        self.tx_display_path = HOME + utils.persist_get(self.persist, 'Profile', 'path.DEFAULT_TX_DISPLAY')
    
    #---------------------------------------------------------------------
    # GUI generated events (i.e. things that happen when you play with widgets)
  
    #=====================================================================
    # Events for the main window
    def delete_event(self, widget, event, data=None):
     # If you return FALSE in the "delete_event" signal handler,
        # GTK will emit the "destroy" signal. Returning TRUE means
        # you don't want the window to be destroyed.
        # This is useful for popping up 'are you sure you want to quit?'
        # type dialogs.

        # Change FALSE to TRUE and the main window will not be destroyed
        # with a "delete_event".
        return False

    #---------------------------------------------------------------------
    def destroy(self, widget, data=None):
        self.ret = -1
        gtk.main_quit()
     
    #---------------------------------------------------------------------
    def profile_changed(self, widget):
        active_text = self.get_active_text(widget)
        if active_text <> None:
          self.current_profile = active_text
          self.persist.setProfile(active_text)
          description = utils.persist_get(self.persist, 'Profile', 'description')
          self.textbuffer.set_text(description)
          self.execute.set_sensitive(True)
        
    #---------------------------------------------------------------------
    def bquit(self, widget):
        self.quit_callback()
        gtk.main_quit()
    
    #---------------------------------------------------------------------
    def bclose(self, widget):
        self.execute.set_sensitive(False)
        self.close.set_sensitive(False)
        self.refresh.set_sensitive(False)
        self.new_sub.set_sensitive(False)
        self.new_rx_disp.set_sensitive(False)
        self.new_tx.set_sensitive(False)
        self.new_tx_disp.set_sensitive(False)
        self.stop_callback()
       
    #---------------------------------------------------------------------
    def brefresh(self, widget):
        self.stop_callback()
        sleep(2)
        self.persist.setProfile(self.current_profile)
        self.start_callback()
        
    #---------------------------------------------------------------------
    def bexecute(self, widget):
        self.start_callback()
        self.close.set_sensitive(True)
        self.refresh.set_sensitive(True)
        self.new_sub.set_sensitive(True)
        self.new_rx_disp.set_sensitive(True)
        self.new_tx.set_sensitive(True)
        self.new_tx_disp.set_sensitive(True)

    #---------------------------------------------------------------------
    # Launchers
    def bnew_sub(self, widget):
      subprocess.Popen(['python', self.console_path, self.ice_config])
    
    #---------------------------------------------------------------------  
    def bozy_load(self, widget):
      subprocess.Popen(['sh', self.ozy_fw_path])
      
    #---------------------------------------------------------------------
    def bnew_rx_disp(self, widget):
      subprocess.Popen(['python', self.display_path, self.ice_config])
      
    #---------------------------------------------------------------------
    def bnew_tx(self, widget):
      subprocess.Popen(['python', self.tx_console_path, self.ice_config])
      
    #---------------------------------------------------------------------
    def bnew_tx_disp(self, widget):
      subprocess.Popen(['python', self.tx_display_path, self.ice_config])
      
    #=====================================================================
    # Private    
    def get_active_text(self, widget):
      selection = widget.get_selection()
      model, iter = selection.get_selected()
      if iter == None:
        return None
      else:
        return model.get_value(iter, 1)
    
    #---------------------------------------------------------------------  
    def insert_row(self, model, parent, firstcolumn, secondcolumn):
      myiter=model.insert_after(parent,None)
      model.set_value(myiter,0,firstcolumn)
      model.set_value(myiter,1,secondcolumn)
      return myiter

    #=====================================================================
    # Entry point
    def main(self):
        # All PyGTK applications must have a gtk.main(). Control ends here
        # and waits for an event to occur (like a key press or mouse event)
        gtk.main()

